package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.rooms.absrooms.AbsChessRoom;
import com.myk.game.gobangchess.rooms.absrooms.movechess.MoreColorCost;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.utils.Pair;

import java.util.ArrayList;
import java.util.List;

/**
 * 攻城棋
 * 相关资料 https://tieba.baidu.com/p/8868979112?pid=149879028647&cid=0#149879028647
 */
public class TownChessRoom extends AbsChessRoom {

    //++骑带领卒，骑上外城后，墙上的卒可以被移动下城，但是在城上的骑不显示带领落子范围了。 （要不然显示与否只判断当前是否携带了棋子？）
    //++守方骑带领卒移动后，卒是可以上“门“的


    private CacheSign cacheSign; //背景缓存标记
    private final List<int[]> moveArrayList = new ArrayList<>(); // 棋子移动标记
    private List<Chess> chessList; //场上棋子集合
    private Chess choose; //当前选中的棋子
    private Chess leader; //当前带领者

    private static final int shouLine = 3; //守城方营线
    private static final int gongLine = 9; //攻城方营线

    public TownChessRoom(String roomName) {
        super(roomName, "新棋吧友笑笑子弹设计的大型非对称杀王棋，模拟攻城与守城。", "攻城棋", GridsUtils.createEmptyGrids(13, 11), true, true);
        initBackground();
    }

    //棋盘背景的设计
    private void initBackground() {
        float lineWidth = 1f;
        List<Sign> chessboardStyle = new ArrayList<>();
        int maxRow = curGrids.length - 1;
        int maxCol = curGrids[0].length - 1;
        //背景
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(maxRow, maxCol), ColorCost.TABLECLOTH_COLOR, ColorCost.TABLECLOTH_COLOR, 2f, 0, 0));
        //外边线条
        chessboardStyle.add(getPath(0, 0, 0, maxCol, lineWidth, ColorCost.BOARD_LINE));
        chessboardStyle.add(getPath(maxRow, 0, maxRow, maxCol, lineWidth, ColorCost.BOARD_LINE));
        chessboardStyle.add(getPath(0, 0, maxRow, 0, lineWidth, ColorCost.BOARD_LINE));
        chessboardStyle.add(getPath(0, maxCol, maxRow, maxCol, lineWidth, ColorCost.BOARD_LINE));
        //中间线条
        for (int i = 1; i < maxRow; i++) {
            chessboardStyle.add(getPath(i, 0, i, maxCol, lineWidth, ColorCost.BOARD_LINE));
        }
        for (int i = 1; i < maxCol; i++) {
            chessboardStyle.add(getPath(0, i, maxRow, i, lineWidth, ColorCost.BOARD_LINE));
        }
        //斜线条
        chessboardStyle.add(getPath(0, 4, 1, 5, lineWidth, ColorCost.BOARD_LINE));
        chessboardStyle.add(getPath(0, 6, 1, 5, lineWidth, ColorCost.BOARD_LINE));
        chessboardStyle.add(getPath(12, 4, 11, 5, lineWidth, ColorCost.BOARD_LINE));
        chessboardStyle.add(getPath(12, 6, 11, 5, lineWidth, ColorCost.BOARD_LINE));
        //械站区线条
        /*for (int i = shouLine + 1; i <= gongLine-1; i++) {
            chessboardStyle.add(getPath(i, 0, i, maxCol, lineWidth,ColorCost.PURPLE_BOARD_LINE));
        }
        for (int i = 1; i < maxCol; i++) {
            chessboardStyle.add(getPath(shouLine, i, gongLine, i, lineWidth,ColorCost.PURPLE_BOARD_LINE));
        }*/
        //分区线条
        chessboardStyle.add(getPath(shouLine, 0, shouLine, maxCol, lineWidth, ColorCost.BLUE_BOARD_LINE));
        chessboardStyle.add(getPath(gongLine, 0, gongLine, maxCol, lineWidth, ColorCost.RED_BOARD_LINE));
        //定位符号
        List<Integer> ti = new ArrayList<>(); //上边的圆点
        List<Integer> bi = new ArrayList<>(); //下边青茎
        for (int i = 0; i <= maxCol; i++) {
            ti.add(getIndex(3, i));
            if (i % 2 == 0) {
                if (i > 0 && i < maxCol) {
                    bi.add(getIndex(9, i));
                }
            }
        }
        ti.add(getIndex(6, 3));
        ti.add(getIndex(6, 5));
        ti.add(getIndex(6, 7));
        ti.add(getIndex(9, 5));
        List<Integer> li = new ArrayList<>(); //左靠青茎
        li.add(getIndex(6, 4));
        li.add(getIndex(6, 8));
        List<Integer> bli = new ArrayList<>(); //左靠青茎
        bli.add(getIndex(9, 10));
        List<Integer> ri = new ArrayList<>(); //右靠青茎
        ri.add(getIndex(6, 2));
        ri.add(getIndex(6, 6));
        List<Integer> bri = new ArrayList<>(); //右靠青茎
        bri.add(getIndex(9, 0));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(ti, ColorCost.BLACK).setCompPoint(0, 0, 0, 0, 0, 0, 0, 0, 1));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(bi, ColorCost.BLACK).setCompAngle(0, 0, 0, 0, 1, 1, 1, 1));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(li, ColorCost.BLACK).setCompAngle(0, 0, 0, 0, 1, 0, 0, 0));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(ri, ColorCost.BLACK).setCompAngle(0, 0, 0, 0, 0, 1, 0, 0));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(bli, ColorCost.BLACK).setCompAngle(0, 0, 0, 0, 1, 0, 0, 1));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(bri, ColorCost.BLACK).setCompAngle(0, 0, 0, 0, 0, 1, 1, 0));
        cacheSign = new CacheSign(this, "background", 21, true, chessboardStyle); //*** 修改背景样式记得改这里的版本号！！！
    }

    //棋盘背景路径绘制方法
    private PathSign getPath(final int fRow, final int fCol, final int tRow, final int tCol, final float size, String color) {
        List<Pair<Integer, Integer>> nodes = new ArrayList<>();
        nodes.add(new Pair<>(getIndex(fRow, fCol), 4));
        nodes.add(new Pair<>(getIndex(tRow, tCol), 4));
        return new PathSign(nodes, color, color, size, 0);
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    @Override
    public String getRuleText() {
        return "                        {{攻城棋·规则介绍@scale=1.3@color=#FF000000}}\n" +
                "{{主题：@color=#FF000000@scale=0.7}}{{攻城与守城。@scale=0.6}}\n" +
                "{{棋盘：@color=#FF000000@scale=0.7}}{{整盘纵横11*13。双方阵营为两端11*4。中间为战区，也叫”器械战区“。@scale=0.6}}\n" +
                "{{摆盘：@color=#FF000000@scale=0.7}}{{城墙、城门作为守方防线，喻指古代城池防御；其中“弩、卒”为叠子摆盘，底为“城”子，喻指城墙上的士兵和城防武器。@scale=0.6}}\n" +
                "{{棋子：@color=#FF000000@scale=0.7}}{{共有56个，攻城方23个，守城方33个。@scale=0.6}}\n" +
                "{{分别为：@color=#FF000000@scale=0.7}}{{分别为：騎，步，弓，翼，潜，兵，卒，抛，衝，縱，弩，城，門，府，營。@scale=0.6}}\n" +
                "                           {{攻城方@scale=1.3@color=#FF000000}}\n" +
                "{{攻城方有：@color=#FF000000@scale=0.7}}{{兵、騎、步、弓、翼、抛、衝、縱、營。@scale=0.6}}\n" +
                "{{兵：@color=#FF000000@scale=0.7}}{{走吃不同，走子十字一格。 吃子“┴”，同过河兵卒，能退不能吃。@scale=0.6}}\n" +
                "{{騎：@color=#FF000000@scale=0.7}}{{骑兵将领。走曰，同馬，蹩脚。行吃一体。@scale=0.6}}\n" +
                "{{步：@color=#FF000000@scale=0.7}}{{步兵将领。走十字一至两格。行吃一体。@scale=0.6}}\n" +
                "{{弓：@color=#FF000000@scale=0.7}}{{弓兵将领。斜走X一至两格，行吃一体。注:弓将可吃子上外城,喻射杀。@scale=0.6}}\n" +
                "{{翼：@color=#FF000000@scale=0.7}}{{走子同弓“X”，吃子同兵“┴”。独行，不跟随，不带领。可上空城，不限内外。(假想高武)@scale=0.6}}\n" +
                "{{衝：@color=#FF000000@scale=0.7}}{{冲车（破门槌）。走子前冲1-2格，后退及左右1格。吃子前方1格。@scale=0.6}}\n" +
                "        {{破门为“T”，即，距离“门子”1-2格范围内，若无阻挡可横吃“门子”三个。注：破门叠子同吃。@scale=0.6}}\n" +
                "{{抛：@color=#FF000000@scale=0.7}}{{投石车。走子前冲1-2格，后退及左右1格。吃子前方1格。@scale=0.6}}\n" +
                "        {{破城为“T”，即在距离“城子”1-3格范围内，可无视棋子阻挡，横吃“城子”三个。注：破城叠子同吃。@scale=0.6}}\n" +
                "{{縦：@color=#FF000000@scale=0.7}}{{纵云梯。走子如“象棋车”横坚无限，不吃任何子，靠近城墙时能将“自身田格”内，己方棋子送上城墙(器械除外)，包括吃子上城。@scale=0.6}}\n" +
                "        {{注一：跟随与上城分开，不可同一回合。@scale=0.6}}\n" +
                "        {{注二：每回合只能送一子上城。@scale=0.6}}\n" +
                "{{營：@color=#FF000000@scale=0.7}}{{中军大帐，不动，被吃告负。@scale=0.6}}\n" +
                "                            {{守城方@scale=1.3@color=#FF000000}}\n" +
                "{{守城方有：@color=#FF000000@scale=0.7}}{{卒、騎、步、弓、潜、弩、城、门、府。@scale=0.6}}\n" +
                "{{“卒、骑、步、弓”四子与攻城方设定一至。@color=#FF000000@scale=0.7}}\n" +
                "{{潜：@color=#FF000000@scale=0.7}}{{潜行，奇袭兵。未入敌营前走子同“步”，独行，不吃子，不领不随，可随意下外城;@scale=0.6}}\n" +
                "        {{进入敌营升变为“炮”，在敌营内走吃如象棋炮，若出营则恢复为“潜”。（假想高武）@scale=0.6}}\n" +
                "{{弩：@color=#FF000000@scale=0.7}}{{城防弩。若在“城墙本位”只吃不走（不能走子但可以吃子），可无阻挡吃城外前方“田格”内任意敌子；@scale=0.6}}\n" +
                "        {{吃子后除了回归城墙本位外，不可走子，不可移动，但可消耗一回合直接回归城墙本位，若本位被占、被破坏、则不能回归。即，城弩除了吃子与归位外不可移动。@scale=0.6}}\n" +
                "{{城：@color=#FF000000@scale=0.7}}{{城墙。不动，不可跨越。分城墙内外。可上城，可下城（上城为叠子），分城墙内和城墙外。@scale=0.6}}\n" +
                "        {{城墙内:上下无要求，己方将领兵卒皆可随意上下。@scale=0.6}}\n" +
                "        {{城墙外:上下设定各不同。@scale=0.6}}\n" +
                "        {{    上外城:方式有三种(縱、弓、翼)。 縦:用云梯上城。弓:射杀吃子上城。翼:走子上空城。@scale=0.6}}\n" +
                "        {{    下外城:除“潜”外，皆需吃子下城外，喻“滚石擂木”之类。@scale=0.6}}\n" +
                "{{門：@color=#FF000000@scale=0.7}}{{城门。不动。己方自由通行，即，本方可无视门子的存在而走子，可叠子，可穿越，喻城门开闭，军队进出；@scale=0.6}}\n" +
                "        {{攻方则会被城门阻挡，需破门而入，即，吃掉门子（破门叠子同吃），喻城门防御。@scale=0.6}}" +
                "{{府：@color=#FF000000@scale=0.7}}{{城府，城府，不动，被吃告负。@scale=0.6}}\n" +
                "                            {{带领跟随@scale=1.3@color=#FF000000}}\n" +
                "{{领兵作战：@color=#FF000000@scale=0.7}}{{将领与攻城器械皆可带领兵卒跟随作战。@scale=0.6}}\n" +
                "{{触发方式：@color=#FF000000@scale=0.7}}{{田区触发，以带领者为田心，自身田区内若有己方兵卒，则可触发跟随。@scale=0.6}}\n" +
                "{{带领方式：@color=#FF000000@scale=0.7}}{{带领者移动之前可以指定田区内一个兵卒，移动后，指定的兵卒可以连协移动到带领者新的田区内。@scale=0.6}}\n" +
                "        {{注一:将领在城上不能带领。@scale=0.6}}\n" +
                "        {{注二:跟随不能吃子。@scale=0.6}}\n" +
                "        {{注三:跟随不能上外城。@scale=0.6}}\n" +
                "{{胜负：@color=#FF000000@scale=0.6}}{{攻方，攻占城府为胜。 守方，突进营帐为胜。@scale=0.6}}";
    }

    @Override
    public String getCoordMode() {
        return "40010000";
    }

    @Override
    public String getGameInfo() {
        //先清空棋盘
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        //画棋盘背景
        signList.add(cacheSign);
        //遍历棋子自绘
        if (chessList != null) {
            for (Chess piece : chessList) {
                piece.render();
            }
        }
        //画棋子选中框
        if (choose != null) {
            signList.add(new GroundSign(getIndex(choose.row, choose.col), "#00FFFFFF", "#FF33CC33", 2F, 0, 1));
        }
        //画移动箭头
        for (int[] moveArray : moveArrayList) {
            signList.add(new LineSign(moveArray[0], moveArray[1], ColorCost.MOVE_ARROW_LIGHT, 1));
        }
        return super.getGameInfo();
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        moveArrayList.clear();
        chessList = null;
        choose = null;
    }

    @Override
    protected void onStartPrepare() {
        initChessList();
        noticeBlackMove(); //默认通知黑方先行动
    }

    //初始化棋子列表
    private void initChessList() {
        chessList = new ArrayList<>();
        //守城方棋子
        chessList.add(new Qian(this, 2, 0, 0));
        chessList.add(new Gong(this, 2, 0, 1));
        chessList.add(new Bu(this, 2, 0, 2));
        chessList.add(new Qi(this, 2, 0, 3));
        chessList.add(new Zu(this, 2, 0, 4));
        chessList.add(new Fu(this, 2, 0, 5));
        chessList.add(new Zu(this, 2, 0, 6));
        chessList.add(new Qi(this, 2, 0, 7));
        chessList.add(new Bu(this, 2, 0, 8));
        chessList.add(new Gong(this, 2, 0, 9));
        chessList.add(new Qian(this, 2, 0, 10));
        chessList.add(new Zu(this, 2, 1, 5));
        chessList.add(new Cheng(this, 2, 3, 0));
        chessList.add(new Cheng(this, 2, 3, 1));
        chessList.add(new Cheng(this, 2, 3, 2));
        chessList.add(new Cheng(this, 2, 3, 3));
        chessList.add(new Zu(this, 2, 3, 2));
        chessList.add(new Nu(this, 2, 3, 3));
        chessList.add(new Men(this, 2, 3, 4));
        chessList.add(new Men(this, 2, 3, 5));
        chessList.add(new Men(this, 2, 3, 6));
        chessList.add(new Cheng(this, 2, 3, 7));
        chessList.add(new Cheng(this, 2, 3, 8));
        chessList.add(new Nu(this, 2, 3, 7));
        chessList.add(new Zu(this, 2, 3, 8));
        chessList.add(new Cheng(this, 2, 3, 9));
        chessList.add(new Cheng(this, 2, 3, 10));
        chessList.add(new Zu(this, 2, 4, 0));
        chessList.add(new Zu(this, 2, 4, 2));
        chessList.add(new Zu(this, 2, 4, 4));
        chessList.add(new Zu(this, 2, 4, 6));
        chessList.add(new Zu(this, 2, 4, 8));
        chessList.add(new Zu(this, 2, 4, 10));
        //攻城方棋子
        chessList.add(new Bing(this, 1, 9, 0));
        chessList.add(new Zong(this, 1, 9, 1));
        chessList.add(new Bing(this, 1, 9, 2));
        chessList.add(new Pao(this, 1, 9, 3));
        chessList.add(new Bing(this, 1, 9, 4));
        chessList.add(new Chong(this, 1, 9, 5));
        chessList.add(new Bing(this, 1, 9, 6));
        chessList.add(new Pao(this, 1, 9, 7));
        chessList.add(new Bing(this, 1, 9, 8));
        chessList.add(new Zong(this, 1, 9, 9));
        chessList.add(new Bing(this, 1, 9, 10));
        chessList.add(new Bing(this, 1, 11, 5));
        chessList.add(new Yi(this, 1, 12, 0));
        chessList.add(new Gong(this, 1, 12, 1));
        chessList.add(new Bu(this, 1, 12, 2));
        chessList.add(new Qi(this, 1, 12, 3));
        chessList.add(new Bing(this, 1, 12, 4));
        chessList.add(new Ying(this, 1, 12, 5));
        chessList.add(new Bing(this, 1, 12, 6));
        chessList.add(new Qi(this, 1, 12, 7));
        chessList.add(new Bu(this, 1, 12, 8));
        chessList.add(new Gong(this, 1, 12, 9));
        chessList.add(new Yi(this, 1, 12, 10));
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (leader != null) {
            leader.putLeadedChess(row, col); //放置带领棋子的新位置
        }
        else if (choose != null) {
            choose.doChooseRule(row, col, value); //交由选中的棋子执行逻辑
        }
        else {
            chooseChess(getChessByPos(row, col)); //选中棋子（可为空）
        }
    }

    //选中棋子
    private void chooseChess(Chess chess) {
        if (choose != null) {
            choose.onCancel();
        }
        choose = chess;
        noticeAllRefreshGameInfo();
    }

    //检测胜负
    private void checkOver() {
        stepAdd();
        if (!hasChessType(chessList, Fu.class)) {
            doOver(cur, getCurPlayer().getNickNameOrTemp() + "攻城成功！！");
            return;
        }
        if (!hasChessType(chessList, Ying.class)) {
            doOver(cur, getCurPlayer().getNickNameOrTemp() + "守城成功！！");
            return;
        }
        changeNoticeMove();//切换行动方
    }

    //切换行动方
    private void changeNoticeMove() {
        if (cur == 1) {
            noticeWhiteMove();
        }
        else {
            noticeBlackMove();
        }
    }

    //根据坐标搜索棋子 (有城门包括城门)
    private List<Chess> getChessesByPos(int row, int col) {
        List<Chess> returnList = new ArrayList<>();
        for (Chess chess : chessList) {
            if (chess.row == row && chess.col == col) {
                returnList.add(chess);
            }
        }
        return returnList;
    }

    //根据坐标搜索棋子 （有多个棋子时取城门之上的棋子, 可为空）
    private Chess getChessByPos(int row, int col) {
        List<Chess> returnList = new ArrayList<>();
        for (Chess chess : chessList) {
            if (chess.row == row && chess.col == col) {
                returnList.add(chess);
            }
        }
        if (returnList.size() == 2) { //如果坐标存在两个棋子，只可能是棋子在城门上，则不要城和门
            returnList.removeIf(chess -> chess.getClass() == Cheng.class || chess.getClass() == Men.class);
        }
        if (returnList.size() == 0) {
            return null; //没用棋子返回空，外界根据空做判断
        }
        return returnList.get(0);//取剩下的城门之上的棋子
    }

    //根据index搜索棋子 (有城门包括城门)
    private List<Chess> getChessesByIndex(int index) {
        List<Chess> returnList = new ArrayList<>();
        for (Chess chess : chessList) {
            if (chess.getIndex() == index) {
                returnList.add(chess);
            }
        }
        return returnList;
    }

    //根据index搜索棋子 （有多个棋子时取城门之上的棋子, 可为空）
    private Chess getChessByIndex(int index) {
        List<Chess> returnList = new ArrayList<>();
        for (Chess chess : chessList) {
            if (chess.getIndex() == index) {
                returnList.add(chess);
            }
        }
        if (returnList.size() == 2) { //如果坐标存在两个棋子，只可能是棋子在城门上，则不要城和门
            returnList.removeIf(chess -> chess.getClass() == Cheng.class || chess.getClass() == Men.class);
        }
        if (returnList.size() == 0) {//没用棋子返回空，外界根据空做判断
            return null;
        }
        return returnList.get(0);//取剩下的城门之上的棋子
    }

    //检测棋子集合中是否包含某个类型的棋子
    private boolean hasChessType(List<Chess> list, Class<? extends Chess> chessType) {
        for (Chess chess : list) {
            if (chess.getClass() == chessType) {
                return true;
            }
        }
        return false;
    }

    /**
     * 棋子公共抽象类
     */
    private abstract static class Chess {

        public TownChessRoom room;
        public String name;
        public int side;
        public int row;
        public int col;
        public boolean leadingFlag; //是否可以领兵标志
        public boolean equipmentFlag; //标记是否攻城器械
        protected Chess ledChess; //被带领的棋子

        public Chess(TownChessRoom room, String name, int side, int row, int col, boolean leadingFlag, boolean equipmentFlag) {
            this.room = room;
            this.name = name;
            this.side = side;
            this.row = row;
            this.col = col;
            this.leadingFlag = leadingFlag;
            this.equipmentFlag = equipmentFlag;
        }

        //获取棋子的坐标索引
        public int getIndex() {
            return room.getIndex(row, col);
        }

        //根据规则搜索棋子默认的移动范围
        protected final List<Integer> genMoveRange(int[][] dxdys, int distance) {
            List<Integer> range = genMoveRange(dxdys, distance, 0, 0);
            range.removeIf(this::isOutOfCheng);//非吃子不能下外城，把属于下外城的范围移除了
            addZongMoveRange(range); //添加纵的走法规则，在己方纵旁边可以借助纵上城
            return range;
        }

        //根据规则搜索棋子默认的移动范围
        protected List<Integer> genMoveRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null && !isSelfMen(chess) && !isGetOnCheng(x, y)) { //除非是自己家的门和自己上外城 ，否则遇到棋子阻碍就得停下
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                        continue;
                    }
                    if (skip >= mustJump) {
                        rangeIndex.add(room.getIndex(x, y));
                        if (isGetOnCheng(x, y)) { //棋子移动止步于上外城，不能穿过城墙
                            break;
                        }
                    }
                }
            }
            return rangeIndex;
        }

        //根据规则搜索棋子默认的吃子范围
        protected final List<Integer> genEatRange(int[][] dxdys, int distance) {
            List<Integer> range = genEatRange(dxdys, distance, 0, 0);
            return range;
        }

        //根据规则搜索棋子默认的吃子范围
        protected List<Integer> genEatRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) {
                        if (chess.side != this.side && skip >= mustJump) {
                            rangeIndex.add(room.getIndex(x, y));
                        }
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                    }
                }
            }
            return rangeIndex;
        }

        //判断这个棋子是否己方的门
        protected boolean isSelfMen(Chess chess) {
            return chess instanceof Men && chess.side == side;
        }

        //判断这个棋子是否己方的城墙
        protected boolean isSelfCheng(Chess chess) {
            return chess instanceof Cheng && chess.side == side;
        }

        //判断这个棋子是否己方的兵卒
        protected boolean isSelfBingZu(Chess chess) {
            if (chess instanceof Bing || chess instanceof Zu) {
                return chess.side == this.side;
            }
            return false;
        }

        //判断这个棋子是否为可被自己带领的兵卒
        protected boolean isLedBingZu(Chess chess) {
            return leadingFlag && isSelfBingZu(chess) && getAroundRange().contains(chess.getIndex());
        }

        //获取自身一周周围的格子（自身为中心“田”区，棋盘范围之外的不加入，最多8个格子）
        protected List<Integer> getAroundRange() {
            int[][] dxdys = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int x = row + dxdy[0];
                int y = col + dxdy[1];
                if (x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length) {
                    rangeIndex.add(room.getIndex(x, y));
                }
            }
            return rangeIndex;
        }

        //获取周围的城墙棋子坐标集合 (type    0:不管城上有没有棋子    1:上面没有棋子的空城      2:上面有对方棋子的城)
        protected List<Integer> getAroundChengRange(int type) {
            List<Integer> aroundRange = getAroundRange();
            if (type == 0){
                aroundRange.removeIf(i -> !room.hasChessType(room.getChessesByIndex(i), Cheng.class));
            }
            else if (type == 1){
                aroundRange.removeIf(i -> !(room.getChessByIndex(i) instanceof Cheng));
            }
            else if (type == 2){
                aroundRange.removeIf(i -> {
                    List<Chess> chesses = room.getChessesByIndex(i);
                    boolean isRemover = chesses.size() != 2 || room.getChessByIndex(i).side == this.side;
                    return isRemover;
                });
            }
            else {
                aroundRange.clear();
            }
            return aroundRange;
        }

        //获取跟随的棋子的可落点范围，（带领者移动后周围一圈，且带领跟随不能吃子，不能上外墙）
        protected List<Integer> getLeadingCanPutRang() {
            int[][] dxdys = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int x = row + dxdy[0];
                int y = col + dxdy[1];
                if (x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length) {
                    if (room.getChessByPos(x, y) == null) {
                        rangeIndex.add(room.getIndex(x, y));
                    }
                }
            }
            return rangeIndex;
        }

        //判断本棋子是否在城墙之上
        protected boolean isOnCheng() {
            return room.hasChessType(room.getChessesByIndex(getIndex()), Cheng.class);
        }

        //判断目标位置是否属于下外城(or穿越城墙)
        protected boolean isOutOfCheng(int tIndex) {
            if (isOnCheng()) {
                int tRow = room.getRowByIndex(tIndex);
                return tRow > this.row;
            }
            return false;
        }

        //判断目标位置是否属于上外城或城上平移
        protected boolean isGetOnCheng(int tRow, int tCol) {
            Chess tChess = room.getChessByPos(tRow, tCol);
            if (tChess instanceof Cheng) { //目标位置是城
                if (isOnCheng()){
                    return this.row == tRow; //城上平移
                }
                else {
                    return this.row < tRow; //上外城
                }
            }
            return false;
        }

        //判断该棋子能否带领
        private boolean isCanLeading() {
            return leadingFlag && !isOnCheng();
        }

        //可吃子范围移除城墙 (若自己就在城上，就不移除)
        protected void removeEatChengRange(List<Integer> range) {
            range.removeIf(index -> {
                List<Chess> chessList = room.getChessesByIndex(index);
                //自己就在城上
                if (isOnCheng()){
                    return room.getChessByIndex(index) instanceof Cheng; //就不能吃城本身（城上的棋子可以吃）
                }
                //自己不在城上
                else {
                    return this.row >= shouLine && room.hasChessType(chessList, Cheng.class); //就不能吃城上的棋子和城本身
                }
            });
        }

        //可移动范围移除阵区（一般是攻城器械不能进入双方进去内）
        protected void removeZhengQuRang(List<Integer> range) {
            range.removeIf(index -> {
                int newRow = room.getRowByIndex(index);
                return newRow < shouLine || newRow > gongLine;
            });
        }

        //增加上纵的移动范围，在己方纵旁边时，可以移动到纵旁边的空城上
        protected void addZongMoveRange(List<Integer> range) {
            if (!equipmentFlag && side == 1){ //非器械棋子才能使用纵云梯，黑方棋子才有纵云梯用
                List<Chess> zongs = getAroundZongs(); //获取旁边的纵云梯
                if (zongs.size()>0){ //有纵云梯的话
                    for (Chess zong : zongs) {
                        range.addAll(zong.getAroundChengRange(1));//获取每个纵云梯各自旁边的空城
                    }
                }
            }
        }

        //获取旁边的棋子纵
        private List<Chess> getAroundZongs() {
            List<Chess> zongs = new ArrayList<>();
            for (Integer index : getAroundRange()) {
                Chess chess = room.getChessByIndex(index);
                if (chess instanceof Zong){
                    zongs.add(chess);
                }
            }
            return zongs;
        }

        //增加上纵的吃子范围，在己方纵旁边时，可以吃纵旁边的城上棋子
        protected void addZongEatRange(List<Integer> range){
            if (!equipmentFlag && side == 1){ //非器械棋子才能使用纵云梯，黑方棋子才有纵云梯用
                List<Chess> zongs = getAroundZongs(); //获取旁边的纵云梯
                if (zongs.size()>0){ //有纵云梯的话
                    for (Chess zong : zongs) {
                        range.addAll(zong.getAroundChengRange(2));//获取每个纵云梯各自旁边的有敌方棋子的城的坐标
                    }
                }
            }
        }

        /**
         * 自定义 获取移动范围
         */
        protected List<Integer> getMoveRange() {
            return new ArrayList<>();
        }

        /**
         * 自定义 获取吃子范围
         */
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }

        /**
         * 棋子自绘渲染
         */
        protected void render() {
            //棋子静态绘制
            renderStatic();
            //本棋子是当前选中的棋子时的绘制
            if (room.choose == this) {
                renderChoose();
            }
            //棋子带领状态绘制
            if (isCanLeading()) {
                renderLeader();
            }
        }

        //棋子带领跟随状态的绘制
        private void renderLeader() {
            //绘制新位置跟随落点范围
            if (room.leader == this) {
                List<Integer> followRange = getLeadingCanPutRang();
                if (followRange.size() > 0) {
                    room.signList.add(new ColorSign(followRange, MoreColorCost.MOVE));
                }
            }
            //绘制标记当前被带领的棋子
            if (ledChess != null) {
                room.signList.add(new BadgeSign(room.getIndex(ledChess.row, ledChess.col), "领", 7, ColorCost.CHESS_RED, ColorCost.TRANSPARENT));
            }
        }

        //棋子静态绘制
        private void renderStatic() {
            room.curGrids[row][col] = side; //显示棋子的底座
            boolean isStack = room.getChessesByPos(row, col).size() > 1; //一个位置大于一个棋子，则认为在城门上叠子摆放，城上绘制为红蓝色，否则为黑白色
            room.signList.add(new TextSign(room.getIndex(row, col), name, isStack ? (side == 1 ? ColorCost.CHESS_RED : ColorCost.CHESS_BLUE) : (side == 1 ? ColorCost.WHITE : ColorCost.BLACK))); //绘制棋子外观
        }

        //本棋子是当前选中的棋子时的绘制
        private void renderChoose() {
            //画一下可移动范围
            for (Integer index : getMoveRange()) {
                room.signList.add(new ColorSign(index, MoreColorCost.MOVE));
            }
            //画一下吃子范围
            for (Integer index : getEatRange()) {
                room.signList.add(new ColorSign(index, MoreColorCost.EAT));
            }
            //如果可以领兵
            if (isCanLeading()) {
                //画一下可以被选中带领的棋子的待选框
                for (Integer index : getAroundRange()) {
                    Chess chess = room.getChessByPos(room.getRowByIndex(index), room.getColByIndex(index));
                    if (isSelfBingZu(chess)) {
                        room.signList.add(new BadgeSign(index, "?", 7, "#FF33CC33", "#FF33CC33"));
                    }
                }
            }
        }

        /**
         * 交由当前选中的棋子执行逻辑
         */
        public void doChooseRule(int row, int col, int value) {
            //本棋子属于触发点击的该玩家
            if (value == side) {
                Chess chess = room.getChessByPos(row, col);
                if (getMoveRange().contains(room.getIndex(row, col))) {
                    doMoveRule(row, col); //执行移子规则
                }
                else if (getEatRange().contains(room.getIndex(row, col))) {
                    doEatRule(chess); //执行吃子规则
                }
                else if (isCanLeading() && isLedBingZu(chess)) {
                    chooseLedChess(chess); //选中要带领的棋子
                }
                else {
                    room.chooseChess(room.getChessByPos(row, col)); //切换选中
                }
            }
            //本棋子不属于触发点击的该玩家
            else {
                room.chooseChess(room.getChessByPos(row, col)); //切换选中
            }
        }

        /**
         * 被取消选中，清除一些前期选中时做的动作
         */
        public void onCancel() {
            ledChess = null; //取消带领的棋子
        }

        //选中带领棋子
        protected void chooseLedChess(Chess chess) {
            this.ledChess = chess;
            room.noticeAllRefreshGameInfo();
        }

        //防止被带领棋子的新位置
        public void putLeadedChess(int row, int col) {
            //所选位置在可放置的范围内
            if (getLeadingCanPutRang().contains(room.getIndex(row, col))){
                //添加跟随者移动标记
                room.moveArrayList.add(new int[]{room.getIndex(ledChess.row, ledChess.col), room.getIndex(row, col)});
                //更新跟随者棋子的坐标
                ledChess.row = row;
                ledChess.col = col;
                //结束后取消带领状态
                ledChess = null;
                room.leader = null;
                //检查回合是否结束（切换行动方）
                room.checkOver();
            }
            //点击空白取消带领棋子的放置
            else if (room.getChessByPos(row,col) == null){
                //结束后取消带领状态
                ledChess = null;
                room.leader = null;
                //检查回合是否结束（切换行动方）
                room.checkOver();
            }
        }

        //移子规则
        public void doMoveRule(int row, int col) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{room.getIndex(this.row, this.col), room.getIndex(row, col)});
            //更新棋子坐标
            this.row = row;
            this.col = col;
            //移动过后选中状态取消
            room.choose = null;
            //是否有带领的棋子，且移动过后有空间可以放
            if (ledChess != null && getLeadingCanPutRang().size() > 0) {
                room.leader = this;
                room.noticeAllRefreshGameInfo();
            }
            else {
                //检查回合是否结束（切换行动方）
                room.checkOver();
            }
        }

        //吃子规则
        public void doEatRule(Chess chess) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{room.getIndex(this.row, this.col), room.getIndex(row, col)});
            //移除被吃棋子
            room.chessList.remove(chess);
            //在判断一下被吃的棋子下方是否有门，有门的话门也被同时吃掉
            Chess men = room.getChessByPos(chess.row, chess.col);
            if (men instanceof Men) {
                room.chessList.remove(men);
            }
            //更新棋子坐标
            this.row = chess.row;
            this.col = chess.col;
            //移动过后选中状态取消
            room.choose = null;
            //是否有带领的棋子，且移动过后有空间可以放
            if (ledChess != null && isCanLeading() && getLeadingCanPutRang().size() > 0) {
                room.leader = this;
                room.noticeAllRefreshGameInfo();
            }
            else {
                //检查回合是否结束（切换行动方）
                room.checkOver();
            }
        }

    }

    //兵 走吃不同，走子十字一格。 吃子“┴”，同过河兵卒，能退不能吃。
    private static class Bing extends Chess {

        public Bing(TownChessRoom room, int side, int row, int col) {
            super(room, "兵", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = genMoveRange(new int[][]{{-1, 0}, {+1, 0}, {0, -1}, {0, +1}}, 1);
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{-1, 0}, {0, -1}, {0, +1}}, 1);
            removeEatChengRange(range);
            addZongEatRange(range);
            return range;
        }
    }

    //卒 走吃不同，走子十字一格。 吃子“┴”，同过河兵卒，能退不能吃。走吃不同，走子十字一格。 吃子“┴”，同过河兵卒，能退不能吃。
    private static class Zu extends Chess {

        public Zu(TownChessRoom room, int side, int row, int col) {
            super(room, "卒", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            //获取基本走法
            List<Integer> range = genMoveRange(new int[][]{{-1, 0}, {+1, 0}, {0, -1}, {0, +1}}, 1);
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{+1, 0}, {0, -1}, {0, +1}}, 1);
            return range;
        }
    }

    //騎 骑兵将领。走曰，同馬，蹩脚。行吃一体。
    private static class Qi extends Chess {

        public Qi(TownChessRoom room, int side, int row, int col) {
            super(room, "騎", side, row, col, true, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = new ArrayList<>();
            Chess block1 = room.getChessByPos(row + 1, col);
            Chess block2 = room.getChessByPos(row - 1, col);
            Chess block3 = room.getChessByPos(row, col + 1);
            Chess block4 = room.getChessByPos(row, col - 1);
            if (block1 == null || isSelfMen(block1)) {
                range.addAll(genMoveRange(new int[][]{{2, 1}, {2, -1}}, 1));
            }
            if (block2 == null || isSelfMen(block2)) {
                range.addAll(genMoveRange(new int[][]{{-2, 1}, {-2, -1}}, 1));
            }
            if (block3 == null || isSelfMen(block3)) {
                range.addAll(genMoveRange(new int[][]{{1, 2}, {-1, 2}}, 1));
            }
            if (block4 == null || isSelfMen(block4)) {
                range.addAll(genMoveRange(new int[][]{{1, -2}, {-1, -2}}, 1));
            }
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = new ArrayList<>();
            Chess block1 = room.getChessByPos(row + 1, col);
            Chess block2 = room.getChessByPos(row - 1, col);
            Chess block3 = room.getChessByPos(row, col + 1);
            Chess block4 = room.getChessByPos(row, col - 1);
            if (block1 == null || isSelfMen(block1)) {
                range.addAll(genEatRange(new int[][]{{2, 1}, {2, -1}}, 1));
            }
            if (block2 == null || isSelfMen(block2)) {
                range.addAll(genEatRange(new int[][]{{-2, 1}, {-2, -1}}, 1));
            }
            if (block3 == null || isSelfMen(block3)) {
                range.addAll(genEatRange(new int[][]{{1, 2}, {-1, 2}}, 1));
            }
            if (block4 == null || isSelfMen(block4)) {
                range.addAll(genEatRange(new int[][]{{1, -2}, {-1, -2}}, 1));
            }
            removeEatChengRange(range);
            addZongEatRange(range);
            return range;
        }
    }

    //步 步兵将领。走十字一至两格。行吃一体。
    private static class Bu extends Chess {

        public Bu(TownChessRoom room, int side, int row, int col) {
            super(room, "步", side, row, col, true, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = genMoveRange(new int[][]{{-1, 0}, {+1, 0}, {0, -1}, {0, +1}}, 2);
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{-1, 0}, {+1, 0}, {0, -1}, {0, +1}}, 2);
            removeEatChengRange(range);
            addZongEatRange(range);
            return range;
        }
    }

    //弓 弓兵将领。斜走X一至两格，行吃一体。注:弓将可吃子上外城,喻射杀。
    private static class Gong extends Chess {

        public Gong(TownChessRoom room, int side, int row, int col) {
            super(room, "弓", side, row, col, true, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = genMoveRange(new int[][]{{-1, -1}, {+1, -1}, {-1, +1}, {+1, +1}}, 2);
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{-1, -1}, {+1, -1}, {-1, +1}, {+1, +1}}, 2);
            range.removeIf(index -> room.getChessByIndex(index) instanceof Cheng); //不能吃城（但是城上有其它棋子就可以吃)
            addZongEatRange(range);
            return range;
        }
    }

    //翼 走子同弓“X”，吃子同兵“┴”。独行，不跟随，不带领。可上空城，不限内外。
    private static class Yi extends Chess {

        public Yi(TownChessRoom room, int side, int row, int col) {
            super(room, "翼", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = this.selfMoveRange(new int[][]{{-1, -1}, {+1, -1}, {-1, +1}, {+1, +1}}, 2, 0, 0);
            return range;
        }

        //翼自定义根据规则搜索棋子默认的移动范围
        private List<Integer> selfMoveRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null && !isSelfMen(chess) && !isGetOnCheng(x, y) && !(chess instanceof Cheng)) { //除非是自己家的门和自己上外城 以及一些能够随意可以越过城的棋子，否则遇到棋子阻碍就得停下
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                        continue;
                    }
                    if (skip >= mustJump) {
                        rangeIndex.add(room.getIndex(x, y));
                        if (room.getChessByPos(x, y) instanceof Cheng) { //棋子移动止步于城，不能穿过城墙
                            break;
                        }
                    }
                }
            }
            addZongMoveRange(rangeIndex);
            return rangeIndex;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{-1, 0}, {0, -1}, {0, +1}}, 1);
            removeEatChengRange(range);
            addZongEatRange(range);
            return range;
        }

    }

    //衝 冲车（破门槌）
    private static class Chong extends Chess {

        public Chong(TownChessRoom room, int side, int row, int col) {
            super(room, "衝", side, row, col, true, true);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = genMoveRange(new int[][]{{-1, 0}}, 2);
            range.addAll(genMoveRange(new int[][]{{1, 0}, {0, -1}, {0, +1}}, 1));
            removeZhengQuRang(range); //攻城器械不能离开器械战区
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{-1, 0}}, 1); //前方1格吃普通棋子
            removeEatChengRange(range);
            List<Integer> range2 = genEatRange(new int[][]{{-1, 0}}, 2); //前方1-2格
            range2.removeIf(i -> !room.hasChessType(room.getChessesByIndex(i), Men.class)); //只能吃门
            range.addAll(range2);
            removeZhengQuRang(range); //攻城器械不能离开器械战区
            return range;
        }

        @Override
        public void doEatRule(Chess chess) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{room.getIndex(this.row, this.col), room.getIndex(row, col)});
            //移除被吃棋子, 若被吃的棋子是门，两边的门和门上的棋子也都一同被吃
            List<Chess> eatenList = room.getChessesByIndex(room.getIndex(chess.row, chess.col)); //获取被吃棋子那一格子所有棋子
            room.chessList.removeAll(eatenList);
            if (room.hasChessType(eatenList, Men.class)) { //被吃的棋子包含门
                List<Chess> leftChesses = room.getChessesByIndex(room.getIndex(chess.row, chess.col - 1));
                if (room.hasChessType(leftChesses, Men.class)) {
                    room.chessList.removeAll(leftChesses);
                }
                List<Chess> rightChesses = room.getChessesByIndex(room.getIndex(chess.row, chess.col + 1));
                if (room.hasChessType(rightChesses, Men.class)) {
                    room.chessList.removeAll(rightChesses);
                }
            }
            //更新棋子坐标
            this.row = chess.row;
            this.col = chess.col;
            //移动过后选中状态取消
            room.choose = null;
            //是否有带领的棋子，且移动过后有空间可以放
            if (ledChess != null && getLeadingCanPutRang().size() > 0) {
                room.leader = this;
                room.noticeAllRefreshGameInfo();
            }
            else {
                //检查回合是否结束（切换行动方）
                room.checkOver();
            }
        }
    }

    //抛 投石车
    private static class Pao extends Chess {

        public Pao(TownChessRoom room, int side, int row, int col) {
            super(room, "抛", side, row, col, true, true);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = genMoveRange(new int[][]{{-1, 0}}, 2);
            range.addAll(genMoveRange(new int[][]{{1, 0}, {0, -1}, {0, +1}}, 1));
            removeZhengQuRang(range); //攻城器械不能离开器械战区
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = genEatRange(new int[][]{{-1, 0}}, 1);
            List<Integer> range2 = genEatRange(new int[][]{{-1, 0}}, 3,2,0); //前方1-3格
            range2.removeIf(i -> !room.hasChessType(room.getChessesByIndex(i), Cheng.class)); //只能吃门
            range.addAll(range2);
            removeZhengQuRang(range); //攻城器械不能离开器械战区
            return range;
        }

        @Override
        public void doEatRule(Chess chess) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{room.getIndex(this.row, this.col), room.getIndex(row, col)});
            //移除被吃棋子, 若被吃的棋子是城，两边的城和城上的棋子也都一同被吃
            List<Chess> eatenList = room.getChessesByIndex(room.getIndex(chess.row, chess.col)); //获取被吃棋子那一格子所有棋子
            room.chessList.removeAll(eatenList);
            if (room.hasChessType(eatenList, Cheng.class)) { //被吃的棋子包含城墙
                List<Chess> leftChesses = room.getChessesByIndex(room.getIndex(chess.row, chess.col - 1));
                if (room.hasChessType(leftChesses, Cheng.class)) {
                    room.chessList.removeAll(leftChesses);
                }
                List<Chess> rightChesses = room.getChessesByIndex(room.getIndex(chess.row, chess.col + 1));
                if (room.hasChessType(rightChesses, Cheng.class)) {
                    room.chessList.removeAll(rightChesses);
                }
            }
            //更新棋子坐标
            this.row = chess.row;
            this.col = chess.col;
            //移动过后选中状态取消
            room.choose = null;
            //是否有带领的棋子，且移动过后有空间可以放
            if (ledChess != null && getLeadingCanPutRang().size() > 0) {
                room.leader = this;
                room.noticeAllRefreshGameInfo();
            }
            else {
                //检查回合是否结束（切换行动方）
                room.checkOver();
            }
        }
    }

    //縦:纵云梯
    private static class Zong extends Chess {

        public Zong(TownChessRoom room, int side, int row, int col) {
            super(room, "縦", side, row, col, true, true);
        }

        @Override
        protected void render() {
            super.render();
            List<Integer> aroundChengRange = getAroundChengRange(0);
            for (Integer index : aroundChengRange) {
                room.signList.add(new LineSign(room.getIndex(this.row, this.col),index,ColorCost.BLACK_TRANSLUCENT, 0));
            }
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = genMoveRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE);
            removeZhengQuRang(range); //攻城器械不能离开器械战区
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>(); //纵不能吃子
        }
    }

    //營：营帐
    private static class Ying extends Chess {

        public Ying(TownChessRoom room, int side, int row, int col) {
            super(room, "營", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            return new ArrayList<>();
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }
    }

    //潜
    private static class Qian extends Chess {

        public Qian(TownChessRoom room, int side, int row, int col) {
            super(room, "潜", side, row, col, false, false);
        }

        @Override
        protected void render() {
            super.render();
            if (isInEnemyCamp()){ //升变角标
                room.signList.add(new BadgeSign(room.getIndex(row, col), "炮", 4, ColorCost.RED_TEXT, ColorCost.WHITE));
            }
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = new ArrayList<>();
            if (isInEnemyCamp()) { //在敌营内走子如象棋炮
                range.addAll(selfMoveRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE,0,0));
            }
            else { //不在敌营走子如步兵将领
                range.addAll(selfMoveRange(new int[][]{{-1, 0}, {+1, 0}, {0, -1}, {0, +1}}, 2,0,0));
            }
            return range;
        }

        //潜和翼自定义根据规则搜索棋子默认的移动范围
        private List<Integer> selfMoveRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null && !isSelfMen(chess) && !isGetOnCheng(x, y) && !(chess instanceof Cheng)) { //除非是自己家的门和自己上外城 以及一些能够随意可以越过城的棋子，否则遇到棋子阻碍就得停下
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                        continue;
                    }
                    if (skip >= mustJump) {
                        rangeIndex.add(room.getIndex(x, y));
                        if (room.getChessByPos(x, y) instanceof Cheng) { //棋子移动止步于城，不能穿过城墙
                            break;
                        }
                    }
                }
            }
            addZongMoveRange(rangeIndex);
            return rangeIndex;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = new ArrayList<>();
            if (isInEnemyCamp()) {//在敌营内
                range.addAll(genEatRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE,1,1));
            }
            return range;
        }

        //判断自身是否在敌营中
        private boolean isInEnemyCamp() {
            return this.row >= 9; //潜属于守城方，它的敌营是攻城方兵线及往下的格子。
        }
    }

    //弩  城防弩。
    private static class Nu extends Chess {

        private int[] originPos; //记录原本的位置
        private int eatingStep; //记录吃子的回合

        public Nu(TownChessRoom room, int side, int row, int col) {
            super(room, "弩", side, row, col, false, false);
            this.originPos = new int[]{row, col};
        }

        @Override
        public void doEatRule(Chess chess) {
            this.eatingStep = room.step; //记录吃子的回合
            super.doEatRule(chess);
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = new ArrayList<>();
            if (this.row != this.originPos[0] || this.col != this.originPos[1]) { //不在原本的位置时
                if (room.step - eatingStep > 1) { //当前回合不是上回合刚吃子
                    if (room.getChessByPos(this.originPos[0], this.originPos[1]) instanceof Cheng) { //原本位置的墙没有被摧毁
                        range.add(room.getIndex(this.originPos[0], this.originPos[1])); //可以走回本位
                    }
                }
            }
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = new ArrayList<>();
            if (this.row == this.originPos[0] && this.col == this.originPos[1]) { //在本位上时
                range.addAll(genEatRange(new int[][]{{1, -1}, {1, 0}, {1, 1}, {2, -1}, {2, 0}, {2, 1}, {3, -1}, {3, 0}, {3, 1}}, 1));//吃城外甲区任意1子，守城方的甲区是本棋子的下方
            }
            return range;
        }
    }

    //城 城墙
    private static class Cheng extends Chess {

        public Cheng(TownChessRoom room, int side, int row, int col) {
            super(room, "城", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            return new ArrayList<>();
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }

        @Override
        public void render() {
            boolean hasOnCheng = room.getChessesByPos(row, col).size() > 1; //一个位置大于一个棋子，则认为有棋在城上
            if (!hasOnCheng) {
                room.curGrids[row][col] = side;
                room.signList.add(new TextSign(room.getIndex(row, col), name, side == 1 ? ColorCost.WHITE : ColorCost.BLACK));
            }
        }
    }

    //門 城门
    private static class Men extends Chess {

        public Men(TownChessRoom room, int side, int row, int col) {
            super(room, "門", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            return new ArrayList<>();
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }

        @Override
        public void render() {
            boolean hasOnCheng = room.getChessesByPos(row, col).size() > 1; //一个位置大于一个棋子，则认为有棋在城上
            if (!hasOnCheng) {
                room.curGrids[row][col] = side;
                room.signList.add(new TextSign(room.getIndex(row, col), name, side == 1 ? ColorCost.WHITE : ColorCost.BLACK));
            }
        }
    }

    //府 城府
    private static class Fu extends Chess {

        public Fu(TownChessRoom room, int side, int row, int col) {
            super(room, "府", side, row, col, false, false);
        }

        @Override
        public List<Integer> getMoveRange() {
            return new ArrayList<>();
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }
    }
}
